import React from 'react'

import * as api from '@/api'
import type { ImageType, IdentifyResItem } from '@/api'

import './upload-bar.less'

export interface UploadBarProps
  extends Pick<React.HTMLAttributes<HTMLDivElement>, 'className' | 'style'> {
  onSelect?: (src?: string) => void
}

interface ImgItemType
  extends Pick<IdentifyResItem, 'id' | 'name' | 'errorMessage'> {
  status: 'loading' | 'error' | 'success'
  src: string
}

export const UploadBar: React.FC<UploadBarProps> = ({
  onSelect,
  ...wrapProps
}) => {
  const inputRef = React.useRef<HTMLInputElement>(null)
  const [imgList, setImgList] = React.useState<ImgItemType[]>([])
  const [newImages, setNewImages] = React.useState<ImageType[]>([])
  const [submiting, setSubmiting] = React.useState(false)
  const [activeItem, setActiveItem] = React.useState<ImgItemType>()
  const imgListRef = React.useRef<typeof imgList>([])

  wrapProps.className = 'upload-bar ' + wrapProps.className || ''

  React.useEffect(() => {
    if (!newImages.length) return
    addImages(newImages)
  }, [newImages])

  React.useEffect(() => {
    // 由于 Promise 过程中无法获取 imgList 数据变更，需要借助此 ref 判断目标是否已被删除
    imgListRef.current = imgList
  }, [imgList])

  /** 新增需要识别的图片 */
  const addImages = React.useCallback(
    (newImages: ImageType[]) => {
      if (!newImages.length) return

      api
        .identify(newImages.map(({ id, src }) => ({ id, src })))
        .then((res) => {
          const nextImgList = [...imgListRef.current]

          res.forEach((item) => {
            const localIndex = nextImgList.findIndex((v) => v.id === item.id)

            if (localIndex === -1) {
              console.error(`元素不存在: ${item.id}, 可能已被删除`)
              return
            }

            if (item.error) {
              nextImgList[localIndex].status = 'error'
              nextImgList[localIndex].errorMessage = item.errorMessage
            } else {
              nextImgList[localIndex].status = 'success'
              nextImgList[localIndex].name = item.name
            }
          })

          setImgList([...nextImgList])
        })

      setNewImages([])
    },
    [imgList]
  )

  /** 处理选择的图片文件 */
  function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
    const { files } = e.target as HTMLInputElement

    api.upload(files).then((resList) => {
      const nextImgList = [...imgList]
      resList.forEach((res) => {
        const itemIndex = nextImgList.findIndex((v) => v.id === res.id)

        if (itemIndex !== -1) {
          console.warn('相同id已存在，跳过处理')
          return
        }

        nextImgList.push({ id: res.id, status: 'loading', src: res.src })
      })

      setImgList(nextImgList)
      setNewImages(resList)
      resetInput()
    })
  }

  /** 检查当前状态是否可保存 */
  const checkCanSave = React.useCallback(() => {
    if (!imgList.length) return false

    for (let index = 0; index < imgList.length; index++) {
      const item = imgList[index]

      if (['loading', 'error'].includes(item.status)) {
        return false
      }
    }
    return true
  }, [imgList])

  /** 删除 */
  function delItem(item: ImgItemType, index: number) {
    const nextImgList = [...imgList]
    nextImgList.splice(index, 1)
    setImgList(nextImgList)

    if (activeItem?.id === item.id) {
      handleSelect()
    }
  }

  /** 处理选中事件 */
  function handleSelect(item?: ImgItemType) {
    onSelect?.(item?.src)
  }

  /** 重置上传队列 */
  function resetInput() {
    if (inputRef.current) {
      inputRef.current.value = ''
    }
  }

  return (
    <div {...wrapProps}>
      <div className="upload-btn">
        <input
          type="file"
          multiple
          accept="image/*"
          ref={inputRef}
          onChange={handleChange}
        />
        <button>Upload</button>
      </div>

      <div className="img-list">
        {imgList.map((item, index) => {
          let content: React.ReactNode = null

          switch (item.status) {
            case 'loading':
              content = <div className="status color-gary">loading...</div>
              break

            case 'error':
              content = (
                <div
                  className="status color-red"
                  onClick={() => alert(item.errorMessage)}
                >
                  Error
                </div>
              )
              break

            case 'success':
              content = (
                <div className='img-item-img'>
                  <img src={item.src} alt="" />
                  <div className="img-item-name">{item.name}</div>
                </div>
              )
              break
          }

          return (
            <div
              key={item.id}
              className={`img-item ${
                activeItem?.id === item.id ? 'active' : ''
              }`}
              onClick={() => {
                setActiveItem(item)
                handleSelect(item)
              }}
            >
              {content}
              <button
                className="img-item-del"
                onClick={(e) => {
                  e.stopPropagation()
                  delItem(item, index)
                }}
              >
                X
              </button>
            </div>
          )
        })}
      </div>

      <div className="save-btn">
        <button
          disabled={!checkCanSave() || submiting}
          onClick={() => {
            setSubmiting(true)
            api
              .save(imgList.map((v) => v.id))
              .then(() => alert('操作完成'))
              .finally(() => setSubmiting(false))
          }}
        >
          {submiting ? 'Saving...' : 'Save'}
        </button>
      </div>
    </div>
  )
}
